package com.meshnetics.gb.stack.mac.primitives;

import com.meshnetics.gb.stack.core.event.StackEventType;
import com.meshnetics.gb.stack.core.event.StackIndication;
import com.meshnetics.gb.stack.core.layer.StackLayer;
import com.meshnetics.gb.stack.mac.RadioMACStackLayer;
import com.meshnetics.gb.stack.mac.type.*;
import com.meshnetics.gb.type.impl.ByteUtils;
import com.meshnetics.gb.type.impl.zcl.Str;
import com.meshnetics.gb.type.impl.zcl.TypeStr;
import com.meshnetics.gb.type.impl.zcl.TypeUInt;
import com.meshnetics.gb.type.impl.zcl.UInt;

import java.nio.ByteBuffer;

/**
 * WRITE DESCRIPTION HERE
 *
 * @author AKovylin
 */
public class MACBeaconNotifyIndication extends StackIndication {
    public static final byte CODE = 0x4c;

    private final UInt bsn;
    private final PANDescriptor panDescriptor;
    private final PendingAddressSpec pendAddrSpec;
    private final BeaconAddrList addrList;
    private final UInt sduLength;
    private final Str sdu;

    public MACBeaconNotifyIndication(ByteBuffer bb, RadioMACStackLayer layer) {
        super("macBeaconNotifyIndication", StackEventType.LME_TYPE, null, layer);
        ByteUtils.ensureNotNull(bb);
        ByteUtils.ensureCapacity(bb, 1);
        this.bsn = (UInt) TypeUInt.UINT_8.deserialize(bb);
        this.panDescriptor = (PANDescriptor) TypePANDescriptor.TYPE.deserialize(bb);
        ByteUtils.ensureCapacity(bb, 1);
        this.pendAddrSpec = (PendingAddressSpec) TypePendingAddressSpec.TYPE.deserialize(bb);
        ByteUtils.ensureCapacity(bb,
                pendAddrSpec.getShortAddressesPending() * 2 + pendAddrSpec.getExtendedAddressesPending() * 8);
        this.addrList = (BeaconAddrList) TypeBeaconAddrList.TYPE.deserialize(bb, pendAddrSpec);
        ByteUtils.ensureCapacity(bb, 1);
        this.sduLength = (UInt) TypeUInt.UINT_8.deserialize(bb);
        if (((Number) sduLength.toObject()).intValue() > 52) {
            throw new IllegalArgumentException("sduLength is greater than 52 (aMaxBeaconPayloadLength)");
        }
        ByteUtils.ensureCapacity(bb, ((Number) sduLength.toObject()).intValue());
        this.sdu = (Str) TypeStr.STRING_OCTET.deserialize(bb, ((Number) sduLength.toObject()).intValue(), false);
    }

    public MACBeaconNotifyIndication(UInt bsn, PANDescriptor panDescriptor, BeaconAddrList addrList) {
        this(bsn, panDescriptor, addrList, (Str) TypeStr.STRING_OCTET.fromObject(new byte[0]));
    }

    public MACBeaconNotifyIndication(UInt bsn, PANDescriptor panDescriptor, BeaconAddrList addrList, Str sdu) {
        this(bsn, panDescriptor, addrList, sdu, null);
    }

    public MACBeaconNotifyIndication(UInt bsn, PANDescriptor panDescriptor, BeaconAddrList addrList, Str sdu,
                                     StackLayer source) {
        super("macBeaconNotifyIndication", StackEventType.LME_TYPE, null, source);
        if (bsn == null) {
            throw new NullPointerException("bsn is null");
        }
        if (panDescriptor == null) {
            throw new NullPointerException("panDescriptor is null");
        }
        if (addrList == null) {
            throw new NullPointerException("addrList is null");
        }
        if (sdu == null) {
            throw new NullPointerException("sdu is null");
        }
        if (!TypeStr.STRING_OCTET.equals(sdu.getType())) {
            throw new IllegalArgumentException("sdu must be octet string");
        }
        if (sdu.getLength() > 52) {
            throw new IllegalArgumentException("sduLength is greater than 52 (aMaxBeaconPayloadLength)");
        }
        this.bsn = bsn.convert(TypeUInt.UINT_8);
        this.panDescriptor = panDescriptor;
        this.pendAddrSpec = addrList.deriveSpec();
        this.addrList = addrList;
        this.sduLength = (UInt) TypeUInt.UINT_8.fromObject(new Integer(sdu.getLength()));
        this.sdu = sdu;
    }

    public UInt getBsnType() {
        return bsn;
    }

    public Byte getBsn() {
        return (Byte) bsn.toObject();
    }

    public PANDescriptor getPanDescriptorType() {
        return panDescriptor;
    }

    public PendingAddressSpec getPendAddrSpecType() {
        return pendAddrSpec;
    }

    public BeaconAddrList getAddrListType() {
        return addrList;
    }

    public Byte getSduLength() {
        return (Byte) sduLength.toObject();
    }

    public UInt getSduLengthType() {
        return sduLength;
    }

    public byte[] getSdu() {
        return (byte[]) sdu.toObject();
    }

    public Str getSduType() {
        return sdu;
    }

    public String toString() {
        return getName() + '(' + bsn + ',' + panDescriptor + ',' + pendAddrSpec + ',' + addrList + ',' +
                sduLength + ',' + sdu + ')';
    }
}
